import java.awt.Color;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import javax.imageio.ImageIO;

/**
 * Takes an image, reduces its resolution, and generates a list of doubles
 * 
 * @author Stephen Mues (sgmr29@gmail.com)
 *
 */
public class ResolutionReductionMethod implements FeatureExtractionMethod {
	//Set to true to see what information is sent to the neural network
	static final boolean VISUALIZE_OUTPUT = true;
	/**
	 * This function generates a list of doubles between 0 and 1 that summarize
	 * the image.  This is achieved by simply reducing the resolution of the image
	 * and returning the brightness of each pixel
	 * 
	 * @param	image	The raw image to be processed
	 * @param	outputLength	The length of the returned list
	 * @return	A list of Doubles between 0 and 1 that summarize the image
	 */
	public ArrayList<Double> process(BufferedImage image, int outputLength)
	{
		//Create the largest square-ish dimensions that can fit within the
		//given output length
		int width = (int) Math.sqrt(outputLength);
		int height = outputLength / width; //Intentional integer division
		ArrayList<Double> result = new ArrayList<Double>();
		
		//Shrink the image to the calculated width/height
		BufferedImage smallBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		Image smallImage;
		smallImage = image.getScaledInstance(width, height, BufferedImage.SCALE_DEFAULT);
		smallBufferedImage.getGraphics().drawImage(smallImage, 0, 0, null);
		
		//Calculate the percieved brightness of each pixel
		BufferedImage greyscaleImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
		for (int x = 0; x < width; ++x)
		{
			for (int y = 0; y < height; ++y)
			{
				Color pixelColor = new Color(smallBufferedImage.getRGB(x, y));
				//Perceived brightness, as defined by stackoverflow:
				//http://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color
				double brightness = 0;
				brightness += 0.299 * pixelColor.getRed() / 255.0;
				brightness += 0.587 * pixelColor.getGreen() / 255.0;
				brightness += 0.114 * pixelColor.getBlue() / 255.0;
				//Don't allow rounding error to take us over 1.0
				if (brightness > 1.0)
				{
					brightness = 1.0;
				}
				result.add(brightness);
				
				if (VISUALIZE_OUTPUT)
				{
					int greyscaleRgb = (int)(brightness * 255);
					greyscaleImage.setRGB(x, y, new Color(greyscaleRgb, greyscaleRgb, greyscaleRgb).getRGB());
				}
			}
		}
		
		//Pad the output with zeroes to match the requested output length
		while (result.size() < outputLength)
		{
			result.add(0.0);
		}
		
		if (VISUALIZE_OUTPUT)
		{
			File outfile = new File("greyscale.png");
			try {
				ImageIO.write(greyscaleImage, "png", outfile);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return result;
	}

	/*
	 * Used by Stephen to manually test this class as he writes it.
	 */
	public static void main(String[] args)
	{
		BufferedImage image = null;
	    URL url;
		try {
			url = new URL("http://upload.wikimedia.org/wikipedia/en/d/d1/Picasso_three_musicians_moma_2006.jpg");
			image = ImageIO.read(url);
			ResolutionReductionMethod processor = new ResolutionReductionMethod();
			ArrayList<Double> result = processor.process(image, ArtCollection.IMAGE_SUMMARY_LENGTH);

			System.out.println(result);
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
